// TestScene.cpp
//
#include "TestScene.h"

#include "QtFwk/UserInteractionManager.h"
#include "QtFwk/MouseStatus.h"

#include "OpenGL/Renderer.h"
#include "OpenGL/OpenGL.h"
#include "Rendering/Camera.h"

#include "Geometry/Geometry.h"
#include "Geometry/Triangulation.h"

#include "Math/Ray.h"
#include "Math/Plane.h"

#include "VObjects/VObjectManager.h"
#include "VObjects/VPoint.h"
#include "VObjects/VMesh.h"
#include "VObjects/VLine.h"
#include "VObjects/VPolyLine.h"
#include "VObjects/VCircle.h"
#include "VObjects/VGroup.h"

#include "CAD/CadEngine.h"
#include "CAD/CadToolSelect.h"
#include "CAD/CadToolCircle.h"
#include "CAD/CadToolErase.h"
#include "CAD/CadToolLine.h"
#include "CAD/CadToolPoint.h"
#include "CAD/CadToolPolygon.h"
#include "CAD/CadToolPolyLine.h"
#include "CAD/CadToolRectangle.h"

#include <QPainter>

#include "Utils/MemCheck.h"
#include "Utils/StringTools.h"

VMesh tea;

// ------------------------------------------------------------------------------------------------
TestScene::TestScene( QWidget *parent )
: GLGraphicsScene(parent)
, _wireframe(false)
, _fonts("")
{
	_objectManager = new VObjectManager(renderer);
	_cadEngine     = new CadEngine(_objectManager);

	_cadEngine->addTool( new CadToolSelect );
	_cadEngine->addTool( new CadToolErase  );
	_cadEngine->addTool( new CadToolPoint  );
	_cadEngine->addTool( new CadToolLine   );
	_cadEngine->addTool( new CadToolPolyLine);
	_cadEngine->addTool( new CadToolCircle );
	_cadEngine->addTool( new CadToolRectangle);
	_cadEngine->addTool( new CadToolPolygon);

	postInitialization();
}

// ------------------------------------------------------------------------------------------------
TestScene::~TestScene()
{
	delete _objectManager;
	delete _cadEngine;
}

// ------------------------------------------------------------------------------------------------
void TestScene::postInitialization()
{
	makeCurrent();


	if( _fonts.load("Resources/arial_small.fnt") )
		renderer->setFont( &_fonts );

	uim->registerMouseCommand( QtFwk::UIMCommand("Zoom",	   "Wheel",			this, &TestScene::zoomScene)      );
	uim->registerMouseCommand( QtFwk::UIMCommand("Pan",		"LeftButton+Drag",	this, &TestScene::translateScene) );
	uim->registerMouseCommand( QtFwk::UIMCommand("Confirm",	"RightButton",		this, &TestScene::confirm) );
	
	uim->registerKeyboardCommand( QtFwk::UIMCommand("Wireframe","W",this, &TestScene::toggleWireframe) );

	//renderer->enableFloatingOrigin();
	
	_camera.lookAt( Math::dvec3(0,0,10), 
		Math::dvec3(0,0,0),
		Math::dvec3(0,1,0)
		);
	
	//_trackball.setCenter( Math::ivec2(width()/2,height()/2) );
	//_trackball.setOrientation( _camera.orientation() );

	VObjectPtr p = std::make_shared<VPoint>(1,1,0);
	VObjectPtr l = std::make_shared<VLine>( Math::dvec3(0), Math::dvec3(-5,-5,0) );
	VObjectPtr c = std::make_shared<VCircle>( Math::dvec3(-4,4,0), 2);
	
	VPointPtr ptr = p->staticCastTo<VPoint>();

	// TEAPOT
	//VObjectPtr m = std::make_shared<VMesh>(Geometry::teapot(10,10));
	//tea = Geometry::teapot(10,10);
	
	std::vector< Math::dvec3 > tripoints;
	for( int i=0; i<3; ++i )
	{
		std::vector< Math::dvec3 > pts;
		
		for( int j=0; j<100; ++j )
			pts.push_back( Math::dvec3(i,2.0*j/100.0,0.0) );
		
		VObjectPtr polyline = std::make_shared<VPolyLine>(pts);
		_objectManager->addObject( polyline );

		tripoints.insert(tripoints.end(), pts.begin(), pts.end() );
	}

	std::vector<unsigned int> tri = Math::Triangulation::triangulate3D( tripoints );

	VMeshPtr mm = VMesh::New(tripoints,tri);
	_objectManager->addObject(mm);
	
	VGroupPtr g = VGroup::New();
	g->addObject(p);
	g->addObject(l);
	g->addObject(c);

	{
		_target = OpenGL::Texture2D::New(GL_RGBA,GL_RGBA,GL_UNSIGNED_BYTE,false,false,512,512,0);
		_depth  = OpenGL::Texture2D::New(GL_RGBA32F,GL_RGBA,GL_FLOAT,false,false,512,512,0);	
		_color  = OpenGL::Texture2D::New(GL_RGBA,GL_RGBA,GL_UNSIGNED_BYTE,false,false,512,512,0);

		_fbo.create();
		bool ok = true;
		ok &= _fbo.attachTextureTarget( _target, GL_COLOR_ATTACHMENT0 );
		ok &= _fbo.attachTextureTarget( _depth,  GL_COLOR_ATTACHMENT1 );
		ok &= _fbo.attachTextureTarget( _color,  GL_COLOR_ATTACHMENT2 );
		ok &= _fbo.attachDepthRenderTarget( GL_DEPTH_COMPONENT24, 512,512 );

		glCheck;

		if( !ok )
			std::cout << _fbo.info() << std::endl;

		_program.attachVertexShader( STRINGIFY(
			varying vec3  v_Normal;
			varying vec3  v_Position;

			void main()
			{				
				vec4 eyespace   = (gl_ModelViewMatrix * gl_Vertex);
				v_Position      = eyespace.xyz;
				v_Normal        = gl_NormalMatrix * gl_Normal;

				gl_Position     = gl_ModelViewProjectionMatrix * gl_Vertex;
				gl_FrontColor   = gl_Color;
			}
		));

		// https://www.opengl.org/wiki/Compute_eye_space_from_window_space#From_gl_FragCoord

		_program.attachFragmentShader( STRINGIFY(
			varying vec3 v_Position;
			varying vec3 v_Normal;

			void main()
			{
				float shininess = 60.0;
				vec3 lightDir   = vec3(0.0,0.0,1.0);
				vec3 ambient    = vec3(0.15);
				vec3      n     = normalize(v_Normal);
				vec3      e     = normalize(-v_Position);
				
				vec3 spec       = vec3(0.0);
				float intensity = max(0.0, dot(n,lightDir));
				if( intensity >= 0.0 )
				{
					vec3 h        = normalize(lightDir+e);
					float intSpec = max(0.0,dot(h,n));
					spec          = vec3(1.0) * pow(intSpec,shininess);
				}
				
				vec3 dstRGB     = max(gl_Color.xyz*intensity+spec, ambient);
				float dstA      = gl_Color.w;

				float lnZ = (v_Position.z/(100.0-0.01));

				gl_FragData[0] = vec4(n * 0.5 + 0.5,1.0);
				gl_FragData[1] = vec4(v_Position,1.0);
				//gl_FragData[1] = vec4(v_Position.x,v_Position.y,lnZ,1.0);
				gl_FragData[2] = vec4(dstRGB,dstA);
			}
		));
		
		_program.compile("SSAO Sampler");

		std::cout << _program.info() << std::endl;

		_ssao.attachVertexShader( STRINGIFY(
		#version 120\n
		uniform vec2 uNearPlaneHalfSize;
		uniform mat4 uInvProjMatrix;
		
		varying vec2 texcoord;
		varying vec3 eyeDirection;

		void main() {
			//   view space position/texcoord:
			texcoord     = gl_Vertex.xy * 0.5 + 0.5;

			// compute eye direction
			//eyeDirection = vec3(2.0 * uNearPlaneHalfSize * texcoord - uNearPlaneHalfSize , -1.0);
			eyeDirection = (uInvProjMatrix * gl_Vertex).xyz;

			//   projected position:
			gl_Position = gl_Vertex;
		}
		));


		_ssao.attachFragmentShader( STRINGIFY(
		#version 120\n
		uniform sampler2D normalTexture;
		uniform sampler2D positionTexture;
		uniform sampler2D colorTexture;
		uniform float uRadius;
		uniform float uPower;

		uniform float camera_near;
		uniform float camera_far;

		int sample_count = 16;
		vec2 poisson16[] = vec2[](    // These are the Poisson Disk Samples
                                vec2( -0.94201624,  -0.39906216 ),
                                vec2(  0.94558609,  -0.76890725 ),
                                vec2( -0.094184101, -0.92938870 ),
                                vec2(  0.34495938,   0.29387760 ),
                                vec2( -0.91588581,   0.45771432 ),
                                vec2( -0.81544232,  -0.87912464 ),
                                vec2( -0.38277543,   0.27676845 ),
                                vec2(  0.97484398,   0.75648379 ),
                                vec2(  0.44323325,  -0.97511554 ),
                                vec2(  0.53742981,  -0.47373420 ),
                                vec2( -0.26496911,  -0.41893023 ),
                                vec2(  0.79197514,   0.19090188 ),
                                vec2( -0.24188840,   0.99706507 ),
                                vec2( -0.81409955,   0.91437590 ),
                                vec2(  0.19984126,   0.78641367 ),
                                vec2(  0.14383161,  -0.14100790 )
                               );

			varying vec2 texcoord;
			varying vec3 eyeDirection;

			/*----------------------------------------------------------------------------*/
			vec3 decodeNormal(in vec3 normal)
			{
			   vec3 n = normal * 2.0 - 1.0;
			   return n;
			}

			/*----------------------------------------------------------------------------*/
			vec3 calculatePosition(in vec2 coord)
			{
				return texture2D(positionTexture, coord).xyz;
				//vec3 viewRay = vec3( eyeDirection.xy * ((camera_far-camera_near)/ eyeDirection.z), (camera_far-camera_near));

				//float normalizedDepth = texture2D(positionTexture, coord).z;
				//return viewRay * normalizedDepth;
			}

			/*----------------------------------------------------------------------------*/
			void main()
			{ 
				vec4 color = texture2D(colorTexture, texcoord);

				if( color.a <= 0.0 )
					discard;

			   vec3 originPos = calculatePosition(texcoord);
			   vec3 normal    = decodeNormal(texture2D(normalTexture, texcoord).rgb);

			   float occlusion = 0.0;
			   for (int i = 0; i < sample_count; ++i)
			   {
				   // sample at an offset specified by the current Poisson-Disk sample and scale it by a radius (has to be in Texture-Space)
				   vec2 sampleTexCoord = texcoord + (poisson16[i] * (uRadius));
				   //float sampleDepth = texture2D(normalTexture, sampleTexCoord).a;
				   vec3 samplePos = calculatePosition(sampleTexCoord);
				   vec3 sampleDir = normalize(samplePos - originPos);

				   // angle between SURFACE-NORMAL and SAMPLE-DIRECTION (vector from SURFACE-POSITION to SAMPLE-POSITION)
				   float NdotS = max(dot(normal, sampleDir), 0);
				   // distance between SURFACE-POSITION and SAMPLE-POSITION
				   float VPdistSP = distance(originPos, samplePos);

				   // a = distance function
				   float a = 1.0 - smoothstep(0, 1, VPdistSP);
				   // b = dot-Product
				   float b = NdotS;

				   occlusion += (a * b);
			   }

			   occlusion = 1.0 - (occlusion / float(sample_count));
			   float ao = pow(occlusion, uPower);   
     

			   gl_FragColor = vec4(vec3(color.rgb * ao),color.a);
			}
			
		));

		
		_ssao.compile("SSAO FSQuad");
		std::cout << _ssao.info() << std::endl;
	}
}

// ------------------------------------------------------------------------------------------------
void TestScene::drawBackground(QPainter *painter, const QRectF &rect)
{
	makeCurrent();

	painter->beginNativePainting();

	glPushAttrib(GL_ALL_ATTRIB_BITS);
	renderer->setClearColor( OpenGL::Color::gray().lighter(0.25),OpenGL::Color::gray().darker(0.15) );
	renderer->clearBackground();
	renderer->setPerspectiveProjection(45, width()/(double)height(),0.01, 100.0 );
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glColor4f(1,1,1,.15);
	glPointSize(4);

	//renderer->setModelView( _camera.matrix()*_trackball.matrix() );
	double scale = 1;//1./renderer->zoomFactor();
	//renderer->setModelView( _trackball.matrix() * Math::scale(Math::dmat4(1), Math::dvec3(scale)) * _camera.matrix() );
	//renderer->setModelView( _camera.matrix() * _trackball.matrix() );
	//renderer->setModelView( _trackball.matrix() * Math::transpose(_camera.matrix()) );
	// 
	// 
	renderer->setModelView( _camera.matrix() * _trackball.matrix() );
	if( _wireframe )
		glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );

#if 0
	_program.bind();
	_fbo.bind(512,512);
	_fbo.clear(0,0,0,0);

	glEnable(GL_LIGHTING);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_LIGHT0);
	glEnable(GL_NORMALIZE);
	glColor3f(0,0,1);
#endif

#if 1
	GLUquadric *q = gluNewQuadric();
	//gluCylinder(q, 1, 1,3,64,64);
	for( int i=0; i<5; ++i )
		for( int j=0; j<5; ++j )
		{
			glPushMatrix();
			glTranslatef(i,j,0);
			gluSphere(q, 0.5,64,64);
			glPopMatrix();
		}
		gluDeleteQuadric(q);
#endif // 0


	//_objectManager->drawObjects();
	//tea.draw(renderer);
#if 0
	glDisable(GL_LIGHTING);
	_program.unbind();
	_fbo.unBind();
//	glCheck;
	_target->dump("normals.tga");
	_depth->dump("depth.tga");
	_color->dump("color.tga");
	glCheck;
#endif

	glBegin(GL_LINES);
	glColor3f(1,0,0); glVertex3f( 0,0,0 ); glVertex3f( 1,0,0 );
	glColor3f(0,1,0); glVertex3f( 0,0,0 ); glVertex3f( 0,1,0 );
	glColor3f(0,0,1); glVertex3f( 0,0,0 ); glVertex3f( 0,0,1 );
	glEnd();

	

	glColor4f(1,1,1,.15);
	int s = 50;
	glBegin( GL_LINES );
	for( int i=-s; i<s; ++i )
	{
		glVertex2i( -s,i );	glVertex2i( s,i );
		glVertex2i( i,-s );	glVertex2i( i,s );
	}
	glEnd();

	glBegin(GL_POINTS);
	glColor3f(0,1,0); glVertex2i(3,1);
	glColor3f(1,1,1);glVertex2i(0,0);
	glEnd();


	
	//_objectManager->drawObjects();
	
	_cadEngine->draw( renderer );

	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	
	_trackball.draw();

	//renderer->addText( Math::ivec2(100,100), "v", OpenGL::Color::white() );

	//renderer->drawText();

	//Math::dmat4 mm = renderer->modelViewMatrix();
	//Math::dmat4 pm = renderer->projectionMatrix();
	//renderer->setScreenSpaceProjection();
	//renderer->setModelView( Math::dmat4(1) );

	//_trackball.draw();
	
	//renderer->setModelView(mm);
	//renderer->setProjection(pm);

	//const Math::dmat4 mm = renderer->modelViewMatrix();
#if 0
	glEnable( GL_BLEND );

	glActiveTexture( GL_TEXTURE0 );
	_target->bind();
	
	glActiveTexture( GL_TEXTURE1 );
	_depth->bind();

	glActiveTexture( GL_TEXTURE2 );
	_color->bind();

	Math::vec2 u;
	double aspect = (width()/(double)height());
	u.y = Math::tan( Math::radians(45.0/2.0) ) * 0.01f;
	u.x = u.y * aspect;

	Math::mat4 inv = Math::inverse(Math::mat4(renderer->projectionMatrix()));

	
	_ssao.bind();
	_ssao.uniform("normalTexture",   0 );
	_ssao.uniform("positionTexture", 1 );
	_ssao.uniform("colorTexture",    2 );
	_ssao.uniformMatrix4("uInvProjMatrix", 1, false, Math::value_ptr(inv) );
	_ssao.uniform2v("uNearPlaneHalfSize", 1, Math::value_ptr(u) );
	_ssao.uniform("camera_near", 0.01f);
	_ssao.uniform("camera_far", 100.f);
	_ssao.uniform("uRadius",10.f/512.f);
	_ssao.uniform("uPower", 3.f );
	glCheck;

	//_ssao.uniform("uTanHalfFov", 0.4142f );
	//_ssao.uniform("uAspectRatio", (float) (width()/(float)height()) );

	glBegin( GL_TRIANGLE_STRIP );
	glVertex2f(-1, 1);
	glVertex2f(-1,-1);
	glVertex2f( 1, 1);
	glVertex2f( 1,-1);
	glEnd();
	_ssao.unbind();
	_target->unbind();
	_depth->unbind();
	_color->unbind();
#endif
	//_target->dump("target.tga");

	//renderer->setModelView(mm);
	//renderer->setProjection(pm);


	
	//_fbo.unBind();
	glPopAttrib();
	glCheck;

	painter->endNativePainting();
}

// ------------------------------------------------------------------------------------------------
void TestScene::rotateScene( double degrees )
{
	//Math::dvec3 centerWS = renderer->convertWindowTo3D( width()/2,height()/2 ); centerWS.z = 0;
	//
	//Math::dvec4 pivot = Math::dvec4(3,1,0,1.0);
	//
	//_camera.rotate(degrees,Math::dvec3(0,0,1), Math::dvec3(pivot) );
}

// ------------------------------------------------------------------------------------------------
void TestScene::zoomScene()
{
	//GLGraphicsScene::zoomScene();
}

// ------------------------------------------------------------------------------------------------
void TestScene::translateScene()
{
	if( _cadEngine->isEnabled() )
		return;

	
	//Math::dvec3 newcenter = renderer->center() - Math::dvec3( diff.x,diff.y, 0.0 );
	
	//renderer->setCenter( newcenter );
		
	updateDrawables();
	invalidate();

	
	//	GLGraphicsScene::translateScene();
}

// ------------------------------------------------------------------------------------------------
void TestScene::toggleWireframe()
{
	_wireframe = !_wireframe;	
}

// ------------------------------------------------------------------------------------------------
void TestScene::confirm()
{
	if( _cadEngine->isEnabled() )
		_cadEngine->confirmTool();
}

// -----------------------------------------------------------------------------------------------
void TestScene::onMousePressed()
{
	const QtFwk::MouseStatus ms = uim->mouseStatus();

	if( _cadEngine->isEnabled() )
	{
		if( ms.buttonDown() & QtFwk::Settings::MainButton )
		{
			//float x = 2.f * ms.currPos().x() / width()  - 1.f;
			//float y = 1.f - (2.f* ms.currPos().y() / height());
			//float z = 1.f;

			//Math::vec3 ray_nds(x,y,z);
			//Math::dvec4 ray_clip( x,y,-1.0, 1.0);
			//Math::dvec4 ray_eye = Math::inverse( renderer->projectionMatrix() ) * ray_clip;
			//
			//ray_eye = Math::dvec4( ray_eye.x,ray_eye.y,-1.0,0.0);
			//
			//Math::dvec3 ray_world = Math::dvec3( Math::inverse( renderer->modelViewMatrix() ) * ray_eye );
			//ray_world = Math::normalize(ray_world);

			//// floor
			//Math::Plane a( Math::dvec3(0,0,1), 0 );

			//double t = - (Math::dot(renderer->eyePosition(),a.normal()) + a.distance()) / ( Math::dot(ray_world,a.normal()) );

			//if( t>0 )
			//{
			//	Math::dvec3 pos( renderer->eyePosition()+ray_world*t );
			//	_cadEngine->startRubberBand( pos );
			//}


			const Math::dvec3 pos( currentWorldPoint.x, currentWorldPoint.y, 0.0 );
			_cadEngine->startRubberBand( pos );
		}
	}
	else
	{
		if( ms.buttonDown() & QtFwk::Settings::SecondaryButton )
			_trackball.startRubberBand( Math::ivec2(currentPixelPoint) );
	}

	invalidate();
}

// -----------------------------------------------------------------------------------------------
void TestScene::onMouseReleased()
{
	const QtFwk::MouseStatus ms = uim->mouseStatus();

	if( _cadEngine->isEnabled() )
	{
		if( uim->mouseStatus().buttonUp() & QtFwk::Settings::MainButton )
		{
			//float x = 2.f * ms.currPos().x() / width()  - 1.f;
			//float y = 1.f - (2.f* ms.currPos().y() / height());
			//float z = 1.f;

			//Math::vec3 ray_nds(x,y,z);
			//Math::dvec4 ray_clip( x,y,-1.0, 1.0);
			//Math::dvec4 ray_eye = Math::inverse( renderer->projectionMatrix() ) * ray_clip;

			//ray_eye = Math::dvec4( ray_eye.x,ray_eye.y,-1.0,0.0);

			//Math::dvec3 ray_world = Math::dvec3( Math::inverse( renderer->modelViewMatrix() ) * ray_eye );
			//ray_world = Math::normalize(ray_world);

			//// floor
			//Math::Plane a( Math::dvec3(0,0,1), 0 );

			//double t = - (Math::dot(renderer->eyePosition(),a.normal()) + a.distance()) / ( Math::dot(ray_world,a.normal()) );

			//if( t>0 )
			//{
			//	Math::dvec3 pos( renderer->eyePosition()+ray_world*t );
			//	_cadEngine->endRubberBand( pos );
			//}


			const Math::dvec3 pos( currentWorldPoint.x, currentWorldPoint.y, 0.0 );
			_cadEngine->endRubberBand( pos );
			_cadEngine->executeCommands();
		}
	}
	else 
	{
		if( ms.buttonUp() & QtFwk::Settings::SecondaryButton )
			_trackball.endRubberBand( Math::ivec2(currentPixelPoint) );
	}

	invalidate();
}

// -----------------------------------------------------------------------------------------------
void TestScene::onMouseMoved()
{
	const QtFwk::MouseStatus ms = uim->mouseStatus();

	if( _cadEngine->isEnabled() )
	{
		const Math::dvec3 pos( currentWorldPoint.x, currentWorldPoint.y, 0.0 );
		_cadEngine->setCurrentPoint( pos );
	}
	else
	{
		if( ms.buttonDown() & QtFwk::Settings::MainButton )
		{

#if 1
			Math::dvec3 n,f;
			Math::dvec3 eye = renderer->eyePosition();
			
			renderer->convertWindowTo3D( ms.prevPos().x(), ms.prevPos().y(),n,f );
			Math::dray prevRay  = Math::dray( eye, Math::normalize(f-n) );

			renderer->convertWindowTo3D( ms.currPos().x(), ms.currPos().y(),n,f );
			Math::dray currRay  = Math::dray( eye, Math::normalize(f-n) );

			Math::dplane plane  = Math::normalize( Math::dplane( eye-_trackball.center(), 0.0));
			//Math::dplane plane = Math::dplane( Math::dvec3(0,0,1), 0.0 );

			double tc,tp;
			if( prevRay.intersects( plane, tp ) && currRay.intersects( plane, tc ) )
			{

				Math::dvec3 t0 = prevRay.pointAt(tp);
				Math::dvec3 t1 = currRay.pointAt(tc);

				_trackball.setCenter(t1-t0);
			}
#endif

#if 0
			Math::dvec3 center( _camera.center() );

			Math::dplane plane    = Math::normalize( Math::dplane( _camera.eye()-center, Math::dot(_camera.eye(),center) ));
			
			Math::dvec3 n,f;
			
			renderer->convertWindowTo3D( ms.prevPos().x(), ms.prevPos().y(),n,f );
			Math::dray prevRay  = Math::dray( _camera.eye(), Math::normalize(f-n) );

			renderer->convertWindowTo3D( ms.currPos().x(), ms.currPos().y(),n,f );
			Math::dray currRay  = Math::dray( _camera.eye(), Math::normalize(f-n) );

			double tc,tp;
			if( prevRay.intersects( plane, tp ) && currRay.intersects( plane, tc ) )
			{

			Math::dvec3 t0 = prevRay.pointAt(tp);
			Math::dvec3 t1 = currRay.pointAt(tc);

			renderer->addText( t0, "t0", OpenGL::Color::white() );
			renderer->addText( t1, "t1", OpenGL::Color::white() );

			Math::dvec3 t = t1-t0;
			Math::dvec3 tt = Math::dvec3(Math::inverse( _trackball.matrix() ) * Math::dvec4(t,1));

			_camera.set( _camera.eye()-tt, _camera.orientation() );
			}
#endif

#if 0
			const Math::dvec2 curr ( renderer->convertWindowTo2D( ms.currPos().x(), ms.currPos().y() ) );
			const Math::dvec2 prev ( renderer->convertWindowTo2D( ms.prevPos().x(), ms.prevPos().y() ) );
			const Math::dvec3 diff = Math::dvec3(curr-prev,0.0);
#endif
#if 0

			const Math::ivec2 curr ( ms.currPos().x(), ms.currPos().y() );
			const Math::ivec2 prev ( ms.prevPos().x(), ms.prevPos().y() );
			Math::dvec2 diff = Math::dvec2(curr-prev) * 0.04;
			diff.y = -diff.y;

			Math::dvec3 t = Math::dmat3(_camera.orientation() ) * Math::dvec3(diff,0);

			Math::dvec3 eye = _camera.eye() - t;

			_camera.set( eye, _camera.orientation() );
#endif

			//Math::dvec3 screenSpaceCenter = renderer->convertWorldToWindow( Math::dvec2(0),false);

			//_trackball.setCenter( Math::ivec2(screenSpaceCenter) );
			//Math::dvec3 center = Math::dvec3(0);
			//Math::dvec3 screenSpaceCenter = Math::project( center, _camera.matrix() * _trackball.matrix(), renderer->projectionMatrix(), renderer->viewport() );
			//_trackball.setCenter( Math::ivec2(screenSpaceCenter) );
		}
		
		if( ms.buttonDown() & QtFwk::Settings::SecondaryButton )
		{
			_trackball.update( Math::ivec2(currentPixelPoint) );
		}
	}

	invalidate();
}

// -----------------------------------------------------------------------------------------------
void TestScene::onMouseWheel()
{
	const QtFwk::MouseStatus ms = uim->mouseStatus();
	const double z              = ms.wheel();

#if 0
	Math::dvec3 n,f; renderer->convertWindowTo3D( width()/2, height()/2, n,f,false );

	Math::dvec3 v = n-f;
	Math::dvec3 u = _camera.center()-f;

	// project u onto v to get the new center
	Math::dvec3 c       = v * (Math::dot(u,v)/Math::dot(v,v)) + f;
	Math::dvec3 eye     = _camera.eye();
	Math::dvec3 viewDir = Math::normalize(c-eye);
	
	if( z > 1. )
		eye = eye + viewDir*0.5;
	else
		eye = eye - viewDir*0.5;


	_camera.lookAt( eye, c/*_camera.center()*/, Math::dvec3(0,1,0) );
	_trackball.setOrientation( _camera.orientation() );
#endif
	_trackball.setZoom(z);

#if 0
	Math::dvec3 t;
	if( z > 1 )	t.z =  1;
	else		t.z = -1;

	t = Math::dmat3(_camera.orientation() ) * t;
	Math::dvec3 eye = _camera.eye() - t;
	
	_camera.set( eye, _camera.orientation() );
#endif
		
	//_trackball.setRadius( _trackball.radius() * z );
	
	
	//renderer->zoomInOut( z );

	//// get the center of the scene
	//Math::dvec3 target( _camera.center() );
	//Math::dvec3 center( _camera.eye() );

	////Math::dvec3 n, f;
	////renderer->convertWindowTo3D(  currentWorldPoint.x,  currentWorldPoint.y, n, f ) ;

	////// Project current center on the near-far segment
	////Math::dvec3 d= (n-f);
	////target= d * ( Math::dot( center - f, d) / Math::dot( d, d ) ) + f;
	////_camera.lookAt( target ); //compute the new center position

	//
	////// get the center of the scene
	////Math::dvec3 target( _camera.center() );
	////Math::dvec3 center( _camera.center() );
	////	
	////target = pos;
	////_camera.lookAt( (center - target)/Math::dvec3(z) + target ); //compute the new center position
	
	_cadEngine->setCurrentPoint( Math::dvec3(currentWorldPoint.x,currentWorldPoint.y,0) );
	
	invalidate();
}

// -----------------------------------------------------------------------------------------------
void TestScene::onMouseDoubleClick()
{
	invalidate();
}

// -----------------------------------------------------------------------------------------------
void TestScene::resizeScene( int w, int h )
{
	GLGraphicsScene::resizeScene(w,h);
	
	_trackball.resize(w,h);
}